package ludo;

import java.io.Serializable;
import java.util.*;

//the engine for a ludo game including validation of rules and game state
public class Engine implements Serializable{

	static final long serialVersionUID = 67458476+5;

	int noPlayers;
	public List<Player> players;
	public int playerInTurn;
	Random rand;
	public int dice;
	List<GameView> listeners;

	public Engine(int n){
		// Initialize game
		noPlayers=n;
		players = new ArrayList<Player>();
		for(int i=0;i<noPlayers;i++){
			players.add(new Player(i));
		}
		rand=new Random();
		listeners = new ArrayList<GameView>();
	}
	public boolean equals(Engine other){
		if (this.noPlayers!=other.noPlayers) return false;
		if (this.dice!=other.dice) return false;
		if (this.playerInTurn!=other.playerInTurn) return false;
		if (this.players.size()!=other.players.size()) return false;
		for (int i = 0; i<players.size(); i++){
			if (!this.players.get(i).equals(other.players.get(i))) return false;
		}
		return true;
	}
	
	
	// Convert from player relative index to game index
	public int index(int i, int player){
		int delta=13;
		if (i>=1 && i<=51){
			int id=i+3+player*delta;
			if (id>55){
				id%=(delta*(player+1));
			}
			return id;
		} else if (i==0){
			return player;
		} else if (i>=51){
			return i+4+player*6;
		}
		return 0;
	}
	
	public void start(){
		playerInTurn=0;
		throwDice();
		for(GameView l: listeners){
			l.update();
		}
	}
	
	public void addView(GameView l){
		listeners.add(l);
	}

	private void throwDice(){
		dice=rand.nextInt(6)+1;
	}

	private void nextTurn(){
		if (dice<6){
			playerInTurn=(playerInTurn+1)%noPlayers;
		}
		//throwDice();
		for(GameView l: listeners){
			l.update();
		}
	}

	// Pass turn -- used when no move is possible
	private boolean pass(){
		if ( dice<6 && getPlayer().getStart()==4){
			nextTurn();
			return true;
		} else {
			return false;
		}
	}
	
	public Player getPlayer(){
		return players.get(playerInTurn);
	}
	
	// Check if current player hit anyone home
	void checkHitHome(int i){
		for(Player p : players ){
			// Only if player has a single piece, and it isn't player's square 1
			if(p!=getPlayer() && p.pieces(i)==1 && p.index(i)!=1){
				p.home(i);
			}
		}
	}
	
	// Move piece at square i according to dice
	public boolean move(int i){
		if (i==-1 ) return pass();
		
		if ( getPlayer().pieces(i)>0){
			// Player hit 6, moves piece into game
			if ( i==playerInTurn && dice==6){
				getPlayer().move(i,1);
				checkHitHome(index(1,playerInTurn));
				nextTurn();
				return true;				
			} else if (i>playerInTurn) {
				getPlayer().move(i, dice);
				checkHitHome(i+dice);
				nextTurn();
				return true;
			}
		}
		return false;
	}
	
	public void setDice(int dice){
		this.dice=dice;
	}

}
